<template>
  <div class="chat-input-container">
    <div class="new-chat-section">
      <button class="new-chat-button" @click="handleNewChat">
        <svg t="1758678310317" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="24742" width="16" height="16">
          <path d="M831.6 639.6h-63.9v127.9H639.9v63.9h127.8v127.9h63.9V831.4h127.9v-63.9H831.6z" p-id="24743" fill="#4285f4"></path>
          <path d="M564.3 925.2c0-18.5-15-33.6-33.6-33.6H287.3c-86.2 0-156.4-70.2-156.4-156.4V286.9c0-86.2 70.1-156.4 156.4-156.4h448.4c86.2 0 156.4 70.2 156.4 156.4v238.8c0 18.5 15 33.6 33.6 33.6s33.6-15 33.6-33.6V286.9C959.2 163.6 859 63.3 735.7 63.3H287.3C164 63.3 63.7 163.6 63.7 286.8v448.3c0 123.2 100.3 223.5 223.6 223.5h243.4c18.6 0.1 33.6-14.9 33.6-33.4z" p-id="24744" fill="#4285f4"></path>
        </svg>
        <span>新建会话</span>
      </button>
    </div>
    
     <div class="input-with-voice-container">
      <div class="input-wrapper">
        <textarea
          v-model="inputText"
          :placeholder="placeholder"
          class="chat-textarea"
          rows="1"
          @input="adjustHeight"
          @keydown="handleKeydown"
          ref="textareaRef"
        ></textarea>
        
        <div class="input-actions">
          <div class="model-selector" @click="toggleDropdown" :class="{ 'disabled': isChatActive }">
            <span class="model-text">{{ selectedCharacter || '请选择人物' }}</span>
            <div v-if="loading" class="loading-indicator">加载中...</div>
            <div v-else-if="error" class="error-message">{{ error }}</div>
            <div v-else-if="!isChatActive" class="dropdown-arrow" :class="{ 'rotate': isDropdownOpen }">
              <!-- ... SVG ... -->
            </div>
            <div class="tooltip-text">此时不允许切换角色，请创建新会话</div>
            
            <div v-if="isDropdownOpen" class="character-dropdown">
              <div 
                v-for="character in characters" 
                :key="character.id"
                class="character-option"
                @click.stop="selectCharacter(character)"
              >
                {{ character.name }}
              </div>
            </div>
          </div>
          <button class="action-button" @click="handleSend" :disabled="!inputText.trim()">
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <line x1="22" y1="2" x2="11" y2="13"/>
              <polygon points="22,2 15,22 11,13 2,9 22,2"/>
            </svg>
          </button>
        </div>
      </div>
      
      <!-- 语音按钮 -->
      <button 
        class="voice-button" 
        @click="toggleVoiceInput"
        :class="{ 'recording': isRecording, 'disabled': !isSpeechRecognitionSupported }"
        :title="isSpeechRecognitionSupported ? (isRecording ? '停止录音' : '开始录音') : '浏览器不支持语音识别'"
      >
        <!-- 录音状态动画 -->
        <div v-if="isRecording" class="recording-animation">
          <div class="pulse"></div>
        </div>
        
        <svg t="1758685594443" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="26724" width="26" height="26">
          <path d="M256 384a42.666667 42.666667 0 0 1 42.666667 42.666667v170.666666a42.666667 42.666667 0 1 1-85.333334 0v-170.666666a42.666667 42.666667 0 0 1 42.666667-42.666667z m170.666667-170.666667a42.666667 42.666667 0 0 1 42.666666 42.666667v512a42.666667 42.666667 0 1 1-85.333333 0V256a42.666667 42.666667 0 0 1 42.666667-42.666667z m170.666666 106.666667a42.666667 42.666667 0 0 1 42.666667 42.666667v298.666666a42.666667 42.666667 0 1 1-85.333333 0V362.666667a42.666667 42.666667 0 0 1 42.666666-42.666667z m170.666667 64a42.666667 42.666667 0 0 1 42.666667 42.666667v192a42.666667 42.666667 0 1 1-85.333334 0v-192a42.666667 42.666667 0 0 1 42.666667-42.666667z" 
            :fill="isRecording ? '#ff0000' : '#d726f1'" 
            p-id="26725">
          </path>
        </svg>
        
        <!-- 不支持提示 -->
        <div v-if="!isSpeechRecognitionSupported" class="unsupported-tooltip">
          ❌
        </div>
      </button>
    </div>
    
    <div class="input-footer">
      <div class="suggestion-chips">
        <div 
          v-for="suggestion in suggestions" 
          :key="suggestion"
          class="suggestion-chip"
          @click="selectSuggestion(suggestion)"
        >
          {{ suggestion }}
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts" name="ChatInput">
import { ref, nextTick, onMounted, watch, onUnmounted } from 'vue'
import axios from 'axios'
import { AppConfig } from '../services/config';

// 定义接口响应类型
interface Character {
  id: string;
  name: string;
}

interface ApiResponseData {
  message: string;
  data: Character[];
}

interface ApiResponse {
  code: number;
  message: string;
  data: ApiResponseData;
}

// 语音识别类型定义
interface SpeechRecognition extends EventTarget {
  continuous: boolean;
  interimResults: boolean;
  lang: string;
  start(): void;
  stop(): void;
  onresult: ((event: SpeechRecognitionEvent) => void) | null;
  onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;
  onend: (() => void) | null;
}

interface SpeechRecognitionEvent extends Event {
  results: SpeechRecognitionResultList;
  resultIndex: number;
}

interface SpeechRecognitionErrorEvent extends Event {
  error: string;
}

interface SpeechRecognitionResult {
  isFinal: boolean;
  [0]: {
    transcript: string;
  };
}

interface SpeechRecognitionResultList {
  [index: number]: SpeechRecognitionResult;
  length: number;
}

declare global {
  interface Window {
    SpeechRecognition: new () => SpeechRecognition;
    webkitSpeechRecognition: new () => SpeechRecognition;
  }
}

// 接收来自父组件的 props
const props = defineProps<{
  isChatActive: boolean,
  currentChatId: string | null,
  selectedSessionCharacterName: string | null
}>()

const emit = defineEmits([
  'new-chat-created',
  'add-message',
  'update-ai-message',
  'new-chat-clicked'
])

const inputText = ref('')
const textareaRef = ref<HTMLTextAreaElement>()
const placeholder = '今天想聊些什么...'
const isStreaming = ref(false)

// 语音识别相关状态
// 新增：用于存储所有已确认的最终识别文本
const baseFinalText = ref('') 
const isRecording = ref(false)
const isSpeechRecognitionSupported = ref(false)
const recognition = ref<SpeechRecognition | null>(null)
// 移除 interimTranscript 和 finalTranscript 状态变量

const suggestions = [
  '你叫什么名字',
  '讲一个故事',
  '你有哪些能力',
  '生活建议'
]

// 语音识别初始化
const initSpeechRecognition = () => {
  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition
  
  if (!SpeechRecognition) {
    console.warn('当前浏览器不支持语音识别功能')
    isSpeechRecognitionSupported.value = false
    return
  }
  
  isSpeechRecognitionSupported.value = true
  recognition.value = new SpeechRecognition()
  
  if (!recognition.value) return
  
  // 配置语音识别
  recognition.value.continuous = true
  recognition.value.interimResults = true
  recognition.value.lang = 'zh-CN'
  
  // 语音识别结果处理 - 修改为追加内容
  recognition.value.onresult = (event: SpeechRecognitionEvent) => {
   let latestTranscript = ''
  let isFinalResult = false

  // 1. 提取本次事件中最新的结果
  for (let i = event.resultIndex; i < event.results.length; i++) {
    const result = event.results[i]
    latestTranscript = result[0].transcript
    if (result.isFinal) {
      isFinalResult = true
    }
  }

  // 如果没有新的转录内容，则退出
  if (!latestTranscript) return

  // 2. 找出用户已有的“非语音”内容
  // 逻辑：将当前输入框内容（inputText）与已确认的语音内容（baseFinalText）进行比较。
  // 超过 baseFinalText 长度的部分，视为用户手动输入的内容（或正在编辑的内容）。
  // 我们只在非 Final 状态下处理这个复杂的逻辑，以防止 onresult 覆盖用户的编辑。
  
  if (isFinalResult) {
    // 3. 处理最终结果 (isFinal: true)
    // 将新确认的最终文本追加到基准文本。
    baseFinalText.value += (baseFinalText.value.trim() ? ' ' : '') + latestTranscript.trim()
    
    // 此时，输入框内容应该严格等于最新的 baseFinalText，以消除所有临时文本。
    // 注意：这个逻辑仍然会导致用户在录音时手动输入的内容被“重置”，这是浏览器API的限制，
    // 因为 isFinal 结果通常会将临时结果清空。
    inputText.value = baseFinalText.value
    
  } else {
    // 4. 处理临时结果 (isFinal: false)
    // 临时结果是持续更新的，每次都用最新的临时文本来替换之前显示的临时文本。
    
    // a. 找出当前 inputText 中，不是由 baseFinalText 贡献的部分（即用户手动输入或前一次的临时文本）
    let currentInput = inputText.value
    let userEditedText = currentInput
    
    // 只有当 baseFinalText 是 inputText 的开头时，我们才尝试计算用户手动输入的部分
    if (baseFinalText.value.length > 0 && currentInput.startsWith(baseFinalText.value)) {
        // 剥离掉已确认的语音文本，剩下的就是用户编辑或临时文本。
        userEditedText = currentInput.substring(baseFinalText.value.length).trim()
    }
    
    // b. 构造新的输入框内容：(baseFinalText) + (用户手动输入/上一次的临时文本) + (最新的临时语音)
    let newTextSegments = []
    
    if (baseFinalText.value.trim()) {
      newTextSegments.push(baseFinalText.value.trim())
    }
    
    // 我们需要一种方法来区分“用户手动输入”和“前一次的临时文本”。
    // 最简单和最少冲突的方式是：在临时结果出现时，我们只显示 "baseFinalText + currentInterimText"
    // **要支持用户手动输入，必须停止 onresult 持续覆盖。**
    
    // 🌟 **终极解决办法：停止覆盖，而是判断**
    // 只有当输入框内容和基准文本一致时，我们才追加临时语音。
    // 如果用户手动编辑了 inputText，那么 onresult 应该**停止**工作，直到用户停止录音或 onresult 返回 isFinal 结果。
    
    // 检查：如果当前输入框内容（inputText）不等于基准文本（baseFinalText），
    // 那么意味着用户在录音开启时手动修改了文本，此时我们不更新 inputText，让用户输入优先。
    if (currentInput.trim() !== baseFinalText.value.trim()) {
      // 此时用户手动输入优先，我们不做任何操作，直到 isFinal 发生。
      // 这个是解决 "麦克风开启状态下文字删除不成功" 的关键。
      console.log('用户手动输入中，onresult 暂停更新。')
      return // 立即返回，不更新 inputText
    }
    
    // 如果输入框内容等于基准文本，说明用户没有手动编辑，此时我们追加临时结果。
    let separator = baseFinalText.value.trim() ? ' ' : ''
    inputText.value = baseFinalText.value.trim() + separator + latestTranscript.trim()
  }

  // 无论如何都调整高度
  adjustHeight()
  }
  
  // 错误处理
  recognition.value.onerror = (event: SpeechRecognitionErrorEvent) => {
    console.error('语音识别错误:', event.error)
    stopRecording()
    
    // 根据错误类型给出用户提示
    switch (event.error) {
      case 'no-speech':
        alert('未检测到语音，请检查麦克风是否正常')
        break
      case 'audio-capture':
        alert('无法访问麦克风，请检查权限设置')
        break
      case 'not-allowed':
        alert('麦克风访问被拒绝，请在浏览器设置中允许麦克风权限')
        break
      default:
        alert('语音识别出现错误，请重试')
    }
  }
  
  // 识别结束处理
  recognition.value.onend = () => {
    if (isRecording.value) {
      // 如果还在录音状态但识别结束了，重新开始（处理超时等情况）
      try {
        recognition.value?.start()
      } catch (error) {
        console.error('重新开始语音识别失败:', error)
        stopRecording()
      }
    }
  }
}

// 开始录音
const startRecording = () => {
  if (!recognition.value || !isSpeechRecognitionSupported.value) {
    alert('浏览器不支持语音识别功能')
    return
  }
  
  try {
    recognition.value.start()
    isRecording.value = true
    console.log('开始语音识别')
  } catch (error) {
    console.error('启动语音识别失败:', error)
    alert('无法启动语音识别，请确保麦克风权限已开启')
  }
}

// 停止录音
const stopRecording = () => {
  if (recognition.value && isRecording.value) {
    try {
      // 🌟 关键修改：在停止识别之前，将当前输入框内容设为最终基准文本
      // 无论用户有没有手动删除，都以当前文本框内容为准
      baseFinalText.value = inputText.value
      recognition.value.stop()
      console.log('停止语音识别，基准文本已更新为:', baseFinalText.value)
    } catch (error) {
      console.error('停止语音识别时出错:', error)
    }
  }
  isRecording.value = false
}

// 切换语音输入状态
const toggleVoiceInput = () => {
  if (!isSpeechRecognitionSupported.value) {
    alert('当前浏览器不支持语音识别功能，请使用Chrome、Edge等现代浏览器')
    return
  }
  
  if (isRecording.value) {
    stopRecording()
  } else {
    startRecording()
  }
}

// 监听 inputText 的变化来同步 baseFinalText
watch(inputText, (newText) => {
  // 只有在非录音状态或当最终文本与当前输入框内容不一致时，才更新 baseFinalText
  // 避免在处理临时结果时，用临时结果去覆盖 baseFinalText
  
  // 我们可以简单地在任何 inputText 变化时，假设这是新的基准文本
  // 因为用户主动删除操作发生在录音停止后。
  
  // **关键修改点：在用户输入框变化时，更新基准文本**
  if (!isRecording.value) {
    baseFinalText.value = newText
  }
  
  // 补充：如果正在录音，我们不修改 baseFinalText，因为 onresult 正在处理它。
  // 但这不会影响您手动删除后的情况，因为手动删除发生在非录音状态。
  
}, { immediate: false })

const adjustHeight = async () => {
  await nextTick()
  if (textareaRef.value) {
    textareaRef.value.style.height = 'auto'
    textareaRef.value.style.height = `${textareaRef.value.scrollHeight}px`
  }
}

const handleKeydown = (event: KeyboardEvent) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault()
    if (!isStreaming.value) {
      handleSend()
    }
  }
}

const handleSend = async () => {
  const messageContent = inputText.value.trim()
  if (!messageContent || isStreaming.value) return
  
  if (!selectedCharacter.value) {
    alert('请先选择一个对话角色！')
    return
  }
  
  const isNewChat = !props.currentChatId
  const chatId = props.currentChatId || generateUUID()
  
  const character = characters.value.find(c => c.name === selectedCharacter.value)
  if (!character) {
      console.error('未找到选定的角色对象')
      alert('选择的角色无效，请重新选择')
      return
  }

  const userMessage = {
    id: generateUUID(),
    role: 'user',
    content: messageContent,
    timestamp: new Date().toISOString()
  }
  
  const aiPlaceholderMessage = {
    id: generateUUID(),
    role: 'assistant',
    content: '正在生成中...',
    timestamp: new Date().toISOString()
  }

  emit('add-message', userMessage)
  emit('add-message', aiPlaceholderMessage)
  
  if (isNewChat) {
    emit('new-chat-created', { newChatId: chatId, characterName: selectedCharacter.value })
  }

  inputText.value = ''
  // **新增：发送后清空基准文本**
  baseFinalText.value = ''
  adjustHeight()

  isStreaming.value = true
  try {
    const response = await fetch(AppConfig.ai.chatUrl + '/ai/chat-and-speech', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        chatId: chatId,
        characterId: character.id,
        message: messageContent,
        url: ""
      })
    })

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const reader = response.body?.getReader()
    if (!reader) {
      throw new Error('无法获取响应流')
    }
    
    const decoder = new TextDecoder('utf-8')
    let aiResponseContent = ''
    
    emit('update-ai-message', { id: aiPlaceholderMessage.id, content: '' })

    while (true) {
      const { done, value } = await reader.read()
      if (done) {
        break
      }
      
      const chunk = decoder.decode(value, { stream: true })
      aiResponseContent += chunk
      emit('update-ai-message', { id: aiPlaceholderMessage.id, content: aiResponseContent })
    }

  } catch (err) {
    console.error('消息发送或流式接收失败:', err)
    const errorMessage = `抱歉，出错了。请检查网络或联系管理员。\n错误信息: ${err instanceof Error ? err.message : '未知错误'}`
    emit('update-ai-message', { id: aiPlaceholderMessage.id, content: errorMessage })
  } finally {
    isStreaming.value = false
  }
}

const selectSuggestion = (suggestion: string) => {
  inputText.value = suggestion
  adjustHeight()
}

const characters = ref<Character[]>([])
const selectedCharacter = ref('')
const isDropdownOpen = ref(false)
const loading = ref(false)
const error = ref('')

const handleNewChat = () => {
  console.log('"新建会话"按钮被点击，触发 new-chat-clicked 事件')
  emit('new-chat-clicked') 
}

watch(() => props.selectedSessionCharacterName, (newName) => {
  if (newName) {
    selectedCharacter.value = newName
  } else {
    selectedCharacter.value = ''
  }
}, { immediate: true })

const toggleDropdown = () => {
  if (props.isChatActive || isStreaming.value) {
    return
  }
  isDropdownOpen.value = !isDropdownOpen.value
}

const fetchCharacterList = async () => {
  loading.value = true
  error.value = ''
  try {
    const response = await axios.get<ApiResponse>(AppConfig.ai.chatUrl + '/ai/getCharacterList')
    if (response.data?.code === 200 && response.data.data?.data) {
      characters.value = response.data.data.data
    } else {
      error.value = response.data?.message || '获取人物列表失败'
    }
  } catch (err) {
    error.value = '网络请求失败'
    console.error('获取人物列表失败', err)
  } finally {
    loading.value = false
  }
}

// 组件挂载时初始化语音识别
onMounted(() => {
  fetchCharacterList()
  initSpeechRecognition()
})

// 组件卸载时停止录音
onUnmounted(() => {
  stopRecording()
})

const selectCharacter = (character: Character) => {
  selectedCharacter.value = character.name
  isDropdownOpen.value = false
  console.log('选择了人物:', character)
}

function generateUUID(): string {
  // 检查浏览器是否支持 crypto.randomUUID()
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
    return crypto.randomUUID();
  }
  
  // 替代方案：使用传统方法生成UUID
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

</script>

<style scoped>
/* 语音按钮样式增强 */
.voice-button {
  position: relative;
  width: 48px;
  height: 48px;
  border: none;
  border-radius: 50%;
  background-color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.15s ease;
  margin-left: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  flex-shrink: 0;
  transform: translateY(-2.5px);
}

.voice-button:hover:not(.disabled) {
  background-color: #f8f9fa;
  transform: scale(1.05);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.voice-button.recording {
  background-color: #ffe6e6;
  animation: pulse 1.5s infinite;
}

.voice-button.disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.voice-button.disabled:hover {
  transform: translateY(-2.5px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* 录音动画 */
.recording-animation {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pulse {
  width: 8px;
  height: 8px;
  background-color: #ff0000;
  border-radius: 50%;
  animation: recording-pulse 1.5s infinite;
}

@keyframes recording-pulse {
  0% {
    transform: scale(0.8);
    opacity: 1;
  }
  50% {
    transform: scale(1.5);
    opacity: 0.7;
  }
  100% {
    transform: scale(0.8);
    opacity: 1;
  }
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(255, 0, 0, 0.4);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(255, 0, 0, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(255, 0, 0, 0);
  }
}

/* 不支持提示 */
.unsupported-tooltip {
  position: absolute;
  top: -5px;
  right: -5px;
  background: #ff4444;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  font-size: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

/* 其他原有样式保持不变 */
.chat-input-container {
  width: 100%;
  max-width: 700px;
}

.new-chat-section {
  display: flex;
  justify-content: flex-start;
  margin-bottom: 16px;
}

.new-chat-button {
  display: flex;
  align-items: center;
  padding: 8px 16px;
  background-color: #e8f0fe;
  border: 1px solid #d2e3fc;
  border-radius: 20px;
  cursor: pointer;
  transition: all 0.2s ease;
  color: #4285f4;
  font-size: 14px;
  transform: translateX(270px);
  margin-bottom: 10px;
  margin-top: -30px;
}

.new-chat-button:hover {
  background-color: #d2e3fc;
  border-color: #4285f4;
  color: #3367d6;
}

.new-chat-button svg {
  margin-right: 8px;
}

.input-with-voice-container {
  display: flex;
  align-items: center;
  position: relative;
}

.input-wrapper {
  position: relative;
  background-color: white;
  border: 1px solid #e5e5e5;
  border-radius: 24px;
  padding: 16px 60px 16px 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  margin-top: -15px;
  width: 100%;
  transform: translateY(5px);
}

.input-wrapper:focus-within {
  border-color: #4285f4;
  box-shadow: 0 2px 12px rgba(66, 133, 244, 0.2);
}

.chat-textarea {
  width: 100%;
  border: none;
  outline: none;
  resize: none;
  font-size: 16px;
  line-height: 1.5;
  color: #333;
  background: transparent;
  min-height: 24px;
  max-height: 200px;
  overflow-y: auto;
}

.chat-textarea::placeholder {
  color: #999;
}

.input-actions {
  position: absolute;
  right: 16px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 12px;
}

.model-selector {
  display: flex;
  align-items: center;
  padding: 6px 12px;
  background-color: #fee8fa;
  border-radius: 20px;
  cursor: pointer;
  transition: background-color 0.2s ease;
  position: relative;
  z-index: 10;
}

.model-selector:hover {
  background-color: #f3caec;
  transform: translateY(-0.5px);
}

.model-selector.disabled {
  background-color: #f5f5f5;
  cursor: not-allowed;
  transform: translateY(0);
}

.model-selector.disabled .model-text {
  color: #aaa;
}

.model-text {
  font-size: 14px;
  color: #aa21cc;
  margin-right: 8px;
  white-space: nowrap;
}

.dropdown-arrow {
  color: #4285f4;
  transition: transform 0.2s ease;
}

.dropdown-arrow.rotate {
  transform: rotate(180deg);
}

.character-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  width: 120px;
  margin-top: 8px;
  background-color: #fee8fa;
  border: 1px solid #f3caec;
  border-radius: 20px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  max-height: 200px;
  overflow-y: auto;
  z-index: 100;
}

.character-option {
  padding: 10px 16px;
  font-size: 14px;
  color: #aa21cc;
  cursor: pointer;
  transition: background-color 0.2s ease;
  border-bottom: 1px solid #f3caec;
}

.character-option:last-child {
  border-bottom: none;
}

.character-option:hover {
  background-color: #f3caec;
  color: #8a1a9d;
}

.tooltip-text {
  visibility: hidden;
  opacity: 0;
  width: max-content;
  max-width: 200px;
  background-color: #333;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 8px 12px;
  font-size: 12px;
  white-space: normal;
  position: absolute;
  z-index: 20;
  bottom: 125%;
  left: 50%;
  transform: translateX(-50%);
  transition: opacity 0.3s;
}

.model-selector.disabled:hover .tooltip-text {
  visibility: visible;
  opacity: 1;
}

.action-button {
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background-color: #4285f4;
  color: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.2s ease, transform 0.1s ease;
}

.action-button:hover:not(:disabled) {
  background-color: #3367d6;
  transform: scale(1.03);
}

.action-button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}

.input-footer {
  margin-top: 16px;
}

.suggestion-chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 12px;
}

.suggestion-chip {
  padding: 8px 16px;
  background-color: white;
  border: 1px solid #e5e5e5;
  border-radius: 20px;
  font-size: 15px;
  color: #666;
  cursor: pointer;
  transition: all 0.2s ease;
}

.suggestion-chip:hover {
  background-color: #f8f9fa;
  border-color: #4285f4;
  color: #4285f4;
  transform: translateY(-1px);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .voice-button {
    width: 44px;
    height: 44px;
    margin-left: 8px;
  }
}
</style>